<template>
    <div>
        <h2>G6 自定义用户卡片节点</h2>
        <div ref="container" style="width:100%;height:300px;background:#f5f5f5;"></div>
    </div>
</template>
<script lang="ts">
export default { name: 'AntvG6Demo2' };
</script>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { Graph, register, Rect, ExtensionCategory } from '@antv/g6';
const container = ref();

// 1. 继承内置节点类型Rect，定义自定义节点UserCardNode
//    可以重写render方法和自定义绘制方法，实现更丰富的节点内容
class UserCardNode extends Rect {
    // 获取当前节点的原始数据（G6 5.x推荐写法）
    get nodeData() {
        return this.context.graph.getNodeData(this.id);
    }
    // 获取节点业务数据
    get data() {
        return this.nodeData.data || {};
    }
    // 头像样式
    getAvatarStyle(attributes: any) {
        const [width, height] = this.getSize(attributes);
        return {
            x: -width / 2 + 10,
            y: -height / 2 + 10,
            width: 30,
            height: 30,
            src: attributes.avatarUrl || '',
            radius: 15, // 圆形头像
        };
    }
    // 绘制头像
    drawAvatarShape(attributes: any, container: any) {
        if (!attributes.avatarUrl) return;
        const avatarStyle = this.getAvatarStyle(attributes);
        this.upsert('avatar', 'image', avatarStyle, container);
    }
    // 状态徽章样式
    getBadgeStyle(attributes: any) {
        const [width, height] = this.getSize(attributes);
        const status = this.data.status || 'offline';
        const colorMap = {
            online: '#52c41a',
            busy: '#faad14',
            offline: '#8c8c8c',
        };
        return {
            x: -width / 2 + 55 + (attributes.username || '').length * 7, // 根据用户名长度动态调整位置
            y: -height / 2 + 20,
            r: 4,
            fill: colorMap[status as keyof typeof colorMap], // 兼容TS类型
            stroke: '#fff',
            lineWidth: 2,
            text: '', // 补充text字段以兼容类型
        };
    }
    // 绘制状态徽章
    drawBadgeShape(attributes: any, container: any) {
        const username = attributes.username || '';
        const [width, height] = this.getSize(attributes);
        const status = this.data.status || 'offline';
        const colorMap = {
            online: '#52c41a',
            busy: '#faad14',
            offline: '#8c8c8c',
        };
        
        // 计算用户名结束位置：起始位置 + 用户名长度 * 字体大小
        const usernameStartX = -width / 2 + 55;
        const usernameEndX = usernameStartX + username.length * 8; // 每个字符约8px
        
        const badgeStyle = {
            // x: usernameEndX - 208, // 用户名结束后留8px间距
            // y: -height / 2 + 20,
            x: 20,
            y:20,
            r: 8,
            fill: colorMap[status as keyof typeof colorMap],
            stroke: '#fff',
            lineWidth: 2,
            text: 'NO',
        };
        console.log('badgeStyle', badgeStyle);
        this.upsert('badge1', 'circle', badgeStyle, container);
    }
    // 用户名样式
    getUsernameStyle(attributes: any) {
        const [width, height] = this.getSize(attributes);
        return {
            x: -width / 2 + 55,
            y: -height / 2 + 20,
            text: attributes.username || '',
            fontSize: 14,
            fill: '#262626',
            fontWeight: 'bold',
            textAlign: 'left',
            textBaseline: 'middle',
        };
    }
    // 绘制用户名
    drawUsernameShape(attributes: any, container: any) {
        if (!attributes.username) return;
        const usernameStyle = this.getUsernameStyle(attributes);
        this.upsert('username', 'text', usernameStyle, container);
    }
    // 角色标签样式
    getRoleStyle(attributes: any) {
        const [width, height] = this.getSize(attributes);
        return {
            x: -width / 2 + 55,
            y: -height / 2 + 35,
            text: attributes.userRole || '',
            fontSize: 11,
            fill: '#8c8c8c',
            textAlign: 'left',
            textBaseline: 'middle',
        };
    }
    // 绘制角色标签
    drawRoleShape(attributes: any, container: any) {
        if (!attributes.userRole) return;
        const roleStyle = this.getRoleStyle(attributes);
        this.upsert('role', 'text', roleStyle, container);
    }
    // 重写render方法，先渲染基础矩形，再渲染自定义内容
    render(attributes: any, container: any) {
        console.log('attributes', attributes);
        super.render(attributes, container); // 渲染基础矩形
        this.drawAvatarShape(attributes, container); // 头像
        this.drawBadgeShape(attributes, container); // 状态徽章
        this.drawUsernameShape(attributes, container); // 用户名
        this.drawRoleShape(attributes, container); // 角色
    }
}

// 2. 注册自定义节点到G6，类型为'user-card-node'
register(ExtensionCategory.NODE, 'user-card-node', UserCardNode);

onMounted(() => {
    // 3. 创建Graph实例，配置节点类型为自定义'user-card-node'，并通过style字段映射业务数据
    const graph = new Graph({
        container: container.value,
        height: 400,
        width: 900,
        data: {
            nodes: [
                {
                    id: 'user1',
                    style: { x: 100, y: 100 }, // 节点位置
                    data: {
                        name: '张小明', // 用户名
                        role: '前端工程师', // 角色
                        status: 'online', // 状态
                        avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Zhang', // 头像
                    },
                },
                {
                    id: 'user2',
                    style: { x: 300, y: 200 }, // 节点位置
                    data: {
                        name: '张小明', // 用户名
                        role: '前端工程师', // 角色
                        status: 'online', // 状态
                        avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Zhang', // 头像
                    },
                },
            ],
        },
        node: {
            type: 'user-card-node', // 指定节点类型为自定义类型
            style: {
                size: [140, 50], // 节点宽高
                fill: '#ffffff',
                stroke: '#d9d9d9',
                lineWidth: 1,
                radius: 6,
                // 通过函数将业务数据映射到节点属性
                avatarUrl: (d: any) => d.data.avatar,
                username: (d: any) => d.data.name,
                userRole: (d: any) => d.data.role,
            },
        },
    });
    // 4. 渲染图
    graph.render();
});
</script> 